package com.healthdata.controller;

import com.healthdata.service.CalculateService;
import com.healthdata.service.ComparisonService;
import com.healthdata.service.DataPreprocessService;
import com.healthdata.service.PaintService;
import com.healthdata.vo.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import weka.core.Instance;
import weka.core.Instances;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@RestController
@RequestMapping("/api/calculate")
//还没跨域！！记得跨域！！
public class CalculateController {

    @Autowired
    private CalculateService calculateService;

    @Autowired
    private ComparisonService comparisonService;

    @Autowired
    private DataPreprocessService dataPreprocessService;

    @Autowired
    private PaintService paintService;

    //单一组的统计计算，包括中位数、平均数、标准差、正太分布、指数分布
    @PostMapping("/statisticalAnalysisSimple")
    public ResponseEntity<Map<String, Object>> statisticalAnalysis(
            @RequestParam("file") MultipartFile file)
    {
        Map<String, Object> response = new HashMap<>();

        Instances data = null;
        String fileExtension = getFileExtension(file.getOriginalFilename());
        switch (fileExtension) {
            case "csv":
                try{
                data = dataPreprocessService.processCSV(file);}catch (IOException e) {
                    e.printStackTrace();
                }
                break;
            case "xlsx":
                try{
                data = dataPreprocessService.processExcel(file);}catch (IOException e) {
                    e.printStackTrace();
                }
                break;
            case "json":
                try{
                data = dataPreprocessService.processJSON(file);}catch (IOException e) {
                    e.printStackTrace();
                }
                break;
            default:
                throw new IllegalArgumentException("不支持的文件格式");
        }

        // 假设第一列数据用于统计分析
        double[] dataArray = data.attributeToDoubleArray(0);

        response.put("status", "success");
        response.put("message", "null");
        response.put("平均数",calculateService.mean(dataArray));
        response.put("中位数",calculateService.median(dataArray));
        response.put("标准差",calculateService.deviation(dataArray));
        response.put("正太",calculateService.testNormal(dataArray));
        response.put("指数",calculateService.testExponential(dataArray));

        HistogramVO histogramVO=paintService.generateHistogram(dataArray);
        response.put("histogram",histogramVO);

        CurveVO curveVO=paintService.generateCurve(dataArray,histogramVO);
        response.put("curve",curveVO);


        return ResponseEntity.status(HttpStatus.OK).body(response);
    }

    //计算一对数据是否线性相关，1为文件中考虑的自变量，2为文件中考虑的因变量
    @PostMapping("/calculateCorrelation")
    public ResponseEntity<Map<String, Object>> calculateCorrelation(
            @RequestParam("file") MultipartFile file,
            @RequestParam("attributeName1") String attributeName1,
            @RequestParam("attributeName2") String attributeName2) {
        Map<String, Object> response = new HashMap<>();

        Instances data = null;
        String fileExtension = getFileExtension(file.getOriginalFilename());
        switch (fileExtension) {
            case "csv":
                try {
                    data = dataPreprocessService.processCSV(file);
                } catch (IOException e) {
                    e.printStackTrace();
                    response.put("status", "error");
                    response.put("message", "处理 CSV 文件时出错");
                    return ResponseEntity.status(HttpStatus.OK).body(response);
                }
                break;
            case "xlsx":
                try {
                    data = dataPreprocessService.processExcel(file);
                } catch (IOException e) {
                    e.printStackTrace();
                    response.put("status", "error");
                    response.put("message", "处理 Excel 文件时出错");
                    return ResponseEntity.status(HttpStatus.OK).body(response);
                }
                break;
            case "json":
                try {
                    data = dataPreprocessService.processJSON(file);
                } catch (IOException e) {
                    e.printStackTrace();
                    response.put("status", "error");
                    response.put("message", "处理 JSON 文件时出错");
                    return ResponseEntity.status(HttpStatus.OK).body(response);
                }
                break;
            default:
                response.put("status", "error");
                response.put("message", "不支持的文件格式");
                return ResponseEntity.status(HttpStatus.OK).body(response);
        }

        // 根据列名查找属性索引
        int attributeIndex1 = findAttributeIndex(data, attributeName1);
        int attributeIndex2 = findAttributeIndex(data, attributeName2);

        if (attributeIndex1 == -1) {
            response.put("status", "error");
            response.put("message", "找不到属性: " + attributeName1);
            return ResponseEntity.status(HttpStatus.OK).body(response);
        }

        if (attributeIndex2 == -1) {
            response.put("status", "error");
            response.put("message", "找不到属性: " + attributeName2);
            return ResponseEntity.status(HttpStatus.OK).body(response);
        }

        List<List<Double>> dataTemp = new ArrayList<>();

        for (int i = 0; i < data.numInstances(); i++) {
            Instance instance = data.instance(i);
            double x = instance.value(attributeIndex1);
            double y = instance.value(attributeIndex2);

            // 创建一个新的 List 来存储 x 和 y 坐标
            List<Double> point = new ArrayList<>();
            point.add(x);  // 将 x 坐标添加到点中
            point.add(y);  // 将 y 坐标添加到点中

            // 将点添加到数据列表
            dataTemp.add(point);
        }
        ScatterVO scatterVO=new ScatterVO(dataTemp);
        response.put("scatterVO",scatterVO);

        CorrelationVO correlationVO = calculateService.calculateCorrelation(data, attributeIndex1, attributeIndex2);

        response.put("status", "success");
        response.put("message", "null");
        response.put("correlationVO", correlationVO);

        return ResponseEntity.status(HttpStatus.OK).body(response);
    }

    //预测线性相关的值，一对数据，自因变量设置和前者一样
    @PostMapping("/predictTrend")
    public ResponseEntity<Map<String, Object>> predictTrend(
            @RequestParam("file") MultipartFile file,
            @RequestParam("directTime") int directTime,
            @RequestParam("attributeName1") String attributeName1,
            @RequestParam("attributeName2") String attributeName2) {
        Map<String, Object> response = new HashMap<>();

        Instances data = null;
        String fileExtension = getFileExtension(file.getOriginalFilename());
        switch (fileExtension) {
            case "csv":
                try {
                    data = dataPreprocessService.processCSV(file);
                } catch (IOException e) {
                    e.printStackTrace();
                    response.put("status", "error");
                    response.put("message", "处理 CSV 文件时出错");
                    return ResponseEntity.status(HttpStatus.OK).body(response);
                }
                break;
            case "xlsx":
                try {
                    data = dataPreprocessService.processExcel(file);
                } catch (IOException e) {
                    e.printStackTrace();
                    response.put("status", "error");
                    response.put("message", "处理 Excel 文件时出错");
                    return ResponseEntity.status(HttpStatus.OK).body(response);
                }
                break;
            case "json":
                try {
                    data = dataPreprocessService.processJSON(file);
                } catch (IOException e) {
                    e.printStackTrace();
                    response.put("status", "error");
                    response.put("message", "处理 JSON 文件时出错");
                    return ResponseEntity.status(HttpStatus.OK).body(response);
                }
                break;
            default:
                response.put("status", "error");
                response.put("message", "不支持的文件格式");
                return ResponseEntity.status(HttpStatus.OK).body(response);
        }

        if (data == null) {
            response.put("status", "error");
            response.put("message", "文件处理失败");
            return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(response);
        }

        // 根据列名查找属性索引
        int attributeIndex1 = findAttributeIndex(data, attributeName1);
        int attributeIndex2 = findAttributeIndex(data, attributeName2);

        if (attributeIndex1 == -1) {
            response.put("status", "error");
            response.put("message", "找不到属性: " + attributeName1);
            return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(response);
        }

        if (attributeIndex2 == -1) {
            response.put("status", "error");
            response.put("message", "找不到属性: " + attributeName2);
            return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(response);
        }

        List<List<Double>> dataTemp = new ArrayList<>();

        for (int i = 0; i < data.numInstances(); i++) {
            Instance instance = data.instance(i);
            double x = instance.value(attributeIndex1);
            double y = instance.value(attributeIndex2);

            // 创建一个新的 List 来存储 x 和 y 坐标
            List<Double> point = new ArrayList<>();
            point.add(x);  // 将 x 坐标添加到点中
            point.add(y);  // 将 y 坐标添加到点中

            // 将点添加到数据列表
            dataTemp.add(point);
        }
        ScatterVO scatterVO=new ScatterVO(dataTemp);
        response.put("scatterVO",scatterVO);

        // 调用服务层方法进行趋势预测
        TrendVO trendVO = calculateService.predictTrend(data, directTime, attributeIndex1, attributeIndex2);
        trendVO.setName1(attributeName1);
        trendVO.setName2(attributeName2);

        response.put("status", "success");
        response.put("message", "null");
        response.put("trendVO", trendVO);

        return ResponseEntity.status(HttpStatus.OK).body(response);
    }

    @PostMapping("/horizontalComparison")
    public ResponseEntity<Map<String, Object>> horizontalComparison(
            @RequestParam("file") MultipartFile file,
            @RequestParam("attributeName1") String attributeName1,
            @RequestParam("attributeName2") String attributeName2) {
        Map<String, Object> response = new HashMap<>();

        Instances data = null;
        String fileExtension = getFileExtension(file.getOriginalFilename());
        switch (fileExtension) {
            case "csv":
                try {
                    data = dataPreprocessService.processCSV(file);
                } catch (IOException e) {
                    e.printStackTrace();
                    response.put("status", "error");
                    response.put("message", "处理 CSV 文件时出错");
                    return ResponseEntity.status(HttpStatus.OK).body(response);
                }
                break;
            case "xlsx":
                try {
                    data = dataPreprocessService.processExcel(file);
                } catch (IOException e) {
                    e.printStackTrace();
                    response.put("status", "error");
                    response.put("message", "处理 Excel 文件时出错");
                    return ResponseEntity.status(HttpStatus.OK).body(response);
                }
                break;
            case "json":
                try {
                    data = dataPreprocessService.processJSON(file);
                } catch (IOException e) {
                    e.printStackTrace();
                    response.put("status", "error");
                    response.put("message", "处理 JSON 文件时出错");
                    return ResponseEntity.status(HttpStatus.OK).body(response);
                }
                break;
            default:
                response.put("status", "error");
                response.put("message", "不支持的文件格式");
                return ResponseEntity.status(HttpStatus.OK).body(response);
        }

        //查找两个对象索引
        int attributeIndex1 = findAttributeIndex(data, attributeName1);
        int attributeIndex2 = findAttributeIndex(data, attributeName2);

        if (attributeIndex1 == -1) {
            response.put("status", "error");
            response.put("message", "找不到属性1: " + attributeName1);
            return ResponseEntity.status(HttpStatus.OK).body(response);
        }

        if (attributeIndex2 == -1) {
            response.put("status", "error");
            response.put("message", "找不到属性2: " + attributeName2);
            return ResponseEntity.status(HttpStatus.OK).body(response);
        }

        //提取目标数据
        double[] data1 = extractScores(data, attributeIndex1);
        double[] data2 = extractScores(data, attributeIndex2);

        //箱线图
        BoxPlotVO boxPlotVO1=paintService.generateBoxPlot(data1);
        BoxPlotVO boxPlotVO2=paintService.generateBoxPlot(data2);
        response.put("boxPlotVO1",boxPlotVO1);
        response.put("boxPlotVO2",boxPlotVO2);

        //检查数据有效性
        if (data1.length == 0 || data2.length == 0) {
            response.put("status", "error");
            response.put("message", "数据为空");
            return ResponseEntity.status(HttpStatus.OK).body(response);
        }


        //调用服务层方法进行水平比较
        HorizonVO horizonVO = comparisonService.horizontalComparison(data1, data2);


        response.put("status", "success");
        response.put("message", "null");
        response.put("horizonVO", horizonVO);

        return ResponseEntity.status(HttpStatus.OK).body(response);
    }

    @PostMapping("/tTest")
    public ResponseEntity<Map<String, Object>> tTest(
            @RequestParam("file") MultipartFile file,
            @RequestParam("attributeName1") String group1ColumnName,
            @RequestParam("attributeName2") String group2ColumnName) {
        Map<String, Object> response = new HashMap<>();

        Instances data = null;
        String fileExtension = getFileExtension(file.getOriginalFilename());
        switch (fileExtension) {
            case "csv":
                try {
                    data = dataPreprocessService.processCSV(file);
                } catch (IOException e) {
                    e.printStackTrace();
                    response.put("status", "error");
                    response.put("message", "处理 CSV 文件时出错");
                    return ResponseEntity.status(HttpStatus.OK).body(response);
                }
                break;
            case "xlsx":
                try {
                    data = dataPreprocessService.processExcel(file);
                } catch (IOException e) {
                    e.printStackTrace();
                    response.put("status", "error");
                    response.put("message", "处理 Excel 文件时出错");
                    return ResponseEntity.status(HttpStatus.OK).body(response);
                }
                break;
            case "json":
                try {
                    data = dataPreprocessService.processJSON(file);
                } catch (IOException e) {
                    e.printStackTrace();
                    response.put("status", "error");
                    response.put("message", "处理 JSON 文件时出错");
                    return ResponseEntity.status(HttpStatus.OK).body(response);
                }
                break;
            default:
                response.put("status", "error");
                response.put("message", "不支持的文件格式");
                return ResponseEntity.status(HttpStatus.OK).body(response);
        }
        if (data == null) {
            response.put("status", "error");
            response.put("message", "文件处理失败");
            return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(response);
        }

        //查找两组数据列的索引
        int group1Index = findAttributeIndex(data, group1ColumnName);
        int group2Index = findAttributeIndex(data, group2ColumnName);

        if (group1Index == -1) {
            response.put("status", "error");
            response.put("message", "找不到第一组数据列: " + group1ColumnName);
            return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(response);
        }

        if (group2Index == -1) {
            response.put("status", "error");
            response.put("message", "找不到第二组数据列: " + group2ColumnName);
            return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(response);
        }

        // 3. 提取两组数据
        double[] group1Data = extractScores(data, group1Index);
        double[] group2Data = extractScores(data, group2Index);

        BoxPlotVO boxPlotVO1=paintService.generateBoxPlot(group1Data);
        BoxPlotVO boxPlotVO2=paintService.generateBoxPlot(group2Data);
        response.put("boxPlotVO1",boxPlotVO1);
        response.put("boxPlotVO2",boxPlotVO2);

        // 4. 检查数据有效性
        if (group1Data.length == 0 || group2Data.length == 0) {
            response.put("status", "error");
            response.put("message", "数据不能为空");
            return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(response);
        }

        // 5. 调用服务层方法进行T检验
        String result = comparisonService.tTest(group1Data, group2Data);

        // 6. 返回结果
        response.put("status", "success");
        response.put("message", "null");
        response.put("tTestResult", result);

        return ResponseEntity.status(HttpStatus.OK).body(response);
    }


    // 从Instances中提取某一列的double值数组
    private double[] extractScores(Instances data, int attributeIndex) {
        double[] scores = new double[data.numInstances()];
        for (int i = 0; i < data.numInstances(); i++) {
            scores[i] = data.instance(i).value(attributeIndex);
        }
        return scores;
    }

    private String getFileExtension(String fileName) {
        int lastIndex = fileName.lastIndexOf('.');
        if (lastIndex != -1) {
            return fileName.substring(lastIndex + 1).toLowerCase();
        }
        return "";
    }

    private int findAttributeIndex(Instances data, String attributeName) {
        for (int i = 0; i < data.numAttributes(); i++) {
//            System.out.println(data.attribute(i).name());
//            System.out.println(attributeName);
            if (data.attribute(i).name().equalsIgnoreCase(attributeName)) {

                return i;
            }
        }
        return -1;
    }


}
